library(data.table)
library(readr)
library(data.table)
library(yfR)
library(ggplot2)
first.date <- Sys.Date() - 5*365
last.date <- Sys.Date()
freq.data <- "daily"
tickers=c('BA','AAPL','A','MSFT','META','^GSPC')
labels = c("BA","AAPL","A","MSFT","META","^GSPC")
output = yf_get(tickers=tickers,first_date=first.date,last_date = last.date,freq_data = freq.data)
ALL500=output
names(ALL500)[9]="return_i"
ALL500=ALL500[,c(1,2,9)]
ALL500=as.data.table(ALL500)
Stats = ALL500[, .(
meanret = mean(return_i, na.rm = TRUE) * 12,
sdret = sd(return_i, na.rm = TRUE) * sqrt(12),
medianret = median(return_i, na.rm = TRUE),
minret = min(return_i, na.rm = TRUE),
maxret = max(return_i, na.rm = TRUE)
),
by = ticker]
Stats
| ticker | meanret | sdret | medianret | minret | maxret |
|---|---|---|---|---|---|
| <chr> | <dbl> | <dbl> | <dbl> | <dbl> | <dbl> |
| ^GSPC | 0.004556954 | 0.04754591 | 0.0007678788 | -0.1198406 | 0.09382774 |
| A | 0.008930504 | 0.06437516 | 0.0013961970 | -0.1101171 | 0.09839413 |
| AAPL | 0.014742331 | 0.07313257 | 0.0012440284 | -0.1286470 | 0.11980831 |
| BA | 0.001456628 | 0.11078314 | -0.0005568453 | -0.2384841 | 0.24318606 |
| META | 0.004807805 | 0.09733720 | 0.0005932430 | -0.2639009 | 0.23282400 |
| MSFT | 0.012118405 | 0.06802626 | 0.0011317886 | -0.1473902 | 0.14216885 |
# Set the risk-free rate of return
rf <- 0.02/12
# Calculate excess returns
Stats[, excess_ret := meanret - rf]
# Calculate Sharpe ratios
Stats[, Sharpe := excess_ret/sdret]
| ticker | meanret | sdret | medianret | minret | maxret | excess_ret | Sharpe |
|---|---|---|---|---|---|---|---|
| <chr> | <dbl> | <dbl> | <dbl> | <dbl> | <dbl> | <dbl> | <dbl> |
| ^GSPC | 0.004556954 | 0.04754591 | 0.0007678788 | -0.1198406 | 0.09382774 | 0.0028902874 | 0.060789396 |
| A | 0.008930504 | 0.06437516 | 0.0013961970 | -0.1101171 | 0.09839413 | 0.0072638374 | 0.112836036 |
| AAPL | 0.014742331 | 0.07313257 | 0.0012440284 | -0.1286470 | 0.11980831 | 0.0130756648 | 0.178794004 |
| BA | 0.001456628 | 0.11078314 | -0.0005568453 | -0.2384841 | 0.24318606 | -0.0002100384 | -0.001895942 |
| META | 0.004807805 | 0.09733720 | 0.0005932430 | -0.2639009 | 0.23282400 | 0.0031411383 | 0.032270686 |
| MSFT | 0.012118405 | 0.06802626 | 0.0011317886 | -0.1473902 | 0.14216885 | 0.0104517379 | 0.153642696 |
returns = dcast(ALL500,ref_date~ticker,value.var = "return_i")
returns = na.omit(returns)
returns = returns[,ref_date:=NULL]
n_assets = 6
N_PORTFOLIOS = 100 # Number of simulations
N_DAYS = 12 # For month to year
avg_returns = colMeans(returns) * N_DAYS
sd_returns = apply(returns,MARGIN = 2,sd) * sqrt(12)
cov_mat = cov(returns) * N_DAYS
#Generate random asset weights
weights = matrix(runif(N_PORTFOLIOS*n_assets), N_PORTFOLIOS, n_assets)
weights = weights/apply(weights, MARGIN = 1, FUN = sum) #Sum of each row is 1
portf_rtns = weights %*% avg_returns
portf_vol = vector(length = N_PORTFOLIOS)
for (i in 1:N_PORTFOLIOS){
portf_vol[i] = sqrt(t(weights[i,]) %*% cov_mat %*% weights[i,])
}
portf_sharpe_ratio = portf_rtns / portf_vol
# data frame with the portfolio metrics
portf_metrics = data.frame(
ticker = rep(paste0(labels, "\n"), each = N_PORTFOLIOS),
rtns = rep(portf_rtns, n_assets),
vol = rep(portf_vol, n_assets),
sharpe = rep(portf_sharpe_ratio, n_assets),
stringsAsFactors = FALSE
)
# Plot the portfolio metrics
ggplot(portf_metrics, aes(x = vol, y = rtns, color = sharpe)) +
geom_point(size = 1.4) +
scale_color_gradient(low = "blue", high = "red") +
labs(title = "Efficient Frontier", x = "Volatility", y = "Expected Return") +
theme_bw() +
theme(plot.title = element_text(hjust = 0.5)) +
annotate("text", x = c(sd_returns), y = c(avg_returns), label = labels, hjust = -0.1, size = 5)
There is a general positive relationship between the standard deviation and the average annualized returns, which means that assets with higher returns tend to have higher risks.
The asset with the highest average annualized return also has the highest standard deviation, which suggests that it is the riskiest asset.
The two assets with the lowest average annualized returns also have the lowest standard deviations, which indicates that they are less risky.
There is one asset with a relatively low standard deviation but a high average annualized return, which could be an attractive option for investors looking for a balance between risk and return.
largest sharpe ratio belongs to AAPL
The six assets have a wide range of average annualized returns, from about 0.15% for BA to over 1.45% for AAPL.
Similarly, the standard deviations of the returns vary widely, from about 0.047 for ^GSPC to over 0.11 for BA and META.
Looking at the scatterplot, we can see a general positive relationship between risk and return. That is, assets with higher returns tend to have higher risks (as measured by standard deviation).
There are a few outliers in the scatterplot. For example, AAPL has the highest return and is also among the assets with the highest risk, while BA has the lowest return and is among the assets with the highest risk.
MSFT is an interesting asset to consider. It has a high return and a relatively low risk, making it a potentially attractive option for investors looking for a balance between risk and return.
Finally, the scatterplot provides a useful visual representation of the risk-return tradeoff for the six assets, which can help investors make informed investment decisions. It is important to note, however, that the scatterplot only shows the relationship between two variables (average annualized return and standard deviation) and should be used in conjunction with other information when making investment decisions.
# maximum Sharpe ratio
maxSharpeIndex = which(portf_sharpe_ratio == max(portf_sharpe_ratio))
# minimum volatility
minVarIndex = which(portf_vol == min(portf_vol))
# Plot maximum Sharpe and minimum variance portfolios
ggplot(portf_metrics, aes(x = vol, y = rtns, color = sharpe)) +
geom_point(size = 1.5) +
scale_color_gradient(low = "blue", high = "red") +
labs(title = "Efficient Frontier", x = "Volatility", y = "Expected Return") +
theme_bw() +
theme(plot.title = element_text(hjust = 0.5)) +
annotate("text", x = c(sd_returns), y = c(avg_returns), label = labels, hjust = -0.2, size = 3) +
geom_vline(xintercept = portf_vol[minVarIndex], linetype = "dashed", color = "grey50") +
geom_hline(yintercept = portf_rtns[minVarIndex], linetype = "dashed", color = "grey50") +
geom_vline(xintercept = portf_vol[maxSharpeIndex], linetype = "dashed", color = "grey50") +
geom_hline(yintercept = portf_rtns[maxSharpeIndex], linetype = "dashed", color = "grey50") +
annotate("text", x = portf_vol[minVarIndex] + 0.005, y = portf_rtns[minVarIndex], label = "Min. Volatility", hjust = 0, size = 3) +
annotate("text", x = portf_vol[maxSharpeIndex] - 0.005, y = portf_rtns[maxSharpeIndex], label = "Max. Sharpe Ratio", hjust = 1, size = 3)
library(PerformanceAnalytics)
library(quantmod)
library(riskParityPortfolio)
library(quadprog)
tickers = c('BA','AAPL','A','MSFT','META')
myAssets <-lapply(tickers, function(x) {
getSymbols(x, from = "2018-03-02", periodicity = "daily",auto.assign=FALSE)})
adjustedPrices <- lapply(myAssets, Ad)
adjustedPrices <- do.call(merge, adjustedPrices)
assetReturns <- Return.calculate(adjustedPrices)[-1]
colnames(assetReturns) <- gsub('.Adjusted', '', colnames(assetReturns), fixed=TRUE)
Sigma <- cov(assetReturns)
N = length(tickers)
b <- rep(1/N, N)
w <- sqrt(b) / sqrt(diag(Sigma))
w <- w / sum(w)
w_Sigmaw <- as.vector(w * (Sigma %*% w))
relative_risk_contribution = w_Sigmaw / sum(w_Sigmaw) # Weights of risk parity
rpp2 = riskParityPortfolio(Sigma,formulation = "diag")
#minimum variance portfolio
Dmat = 2*Sigma
dvec = rep(0, N)
Amat = cbind(rep(1,N),diag(N))
bvec = c(1,rep(0,N))
sol = solve.QP(Dmat=Dmat, dvec=dvec, Amat=Amat, bvec=bvec)
w_minvar=sol$solution
#windows()
# Plot
df1 <- data.frame(Tickers = tickers, Weight = relative_risk_contribution, Portfolio = rep("Risk Parity", N))
df2 <- data.frame(Tickers = tickers, Weight = w_minvar, Portfolio = rep("Minimum Variance", N))
df <- rbind(df1, df2)
ggplot(df, aes(x = Tickers, y = Weight, fill = Portfolio)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Portfolio Weights", x = "Tickers", y = "Weight") +
scale_fill_manual(values = c("#0072B2", "#E69F00"))
# Create data frames
df_minvar <- data.frame(Tickers = c('BA', 'AAPL', 'A', 'MSFT', 'META'),
Weight = c(0.04460382, 0.16019038, 0.51447472, 0.26378634, 0.01694473),
Portfolio = rep("Minimum Variance", 5))
df_riskparity <- data.frame(Tickers = c('BA', 'AAPL', 'A', 'MSFT', 'META'),
Weight = c(0.1674412, 0.2179611, 0.1980224, 0.2241250, 0.1924502),
Portfolio = rep("Risk Parity", 5))
# Write data frames to CSV files
write.csv(df_minvar, "minvar_weights.csv", row.names = FALSE)
write.csv(df_riskparity, "riskparity_weights.csv", row.names = FALSE)
df_minvar
df_riskparity
| Tickers | Weight | Portfolio |
|---|---|---|
| <chr> | <dbl> | <chr> |
| BA | 0.04460382 | Minimum Variance |
| AAPL | 0.16019038 | Minimum Variance |
| A | 0.51447472 | Minimum Variance |
| MSFT | 0.26378634 | Minimum Variance |
| META | 0.01694473 | Minimum Variance |
| Tickers | Weight | Portfolio |
|---|---|---|
| <chr> | <dbl> | <chr> |
| BA | 0.1674412 | Risk Parity |
| AAPL | 0.2179611 | Risk Parity |
| A | 0.1980224 | Risk Parity |
| MSFT | 0.2241250 | Risk Parity |
| META | 0.1924502 | Risk Parity |
The minimum variance portfolio is designed to minimize the portfolio's variance, or volatility. It achieves this by allocating more weight to assets with lower volatility and less weight to assets with higher volatility. In practice, this means that the minimum variance portfolio may be biased towards assets that are traditionally considered less risky, such as bonds, and may underweight more volatile assets, such as equities.
On the other hand, the risk parity portfolio aims to allocate risk equally among the assets in the portfolio. This means that the portfolio will allocate more weight to assets with lower volatility and less weight to assets with higher volatility, but the allocation will be based on each asset's contribution to the overall risk of the portfolio, rather than just its volatility. This approach may lead to a more diversified portfolio, with less concentration in any one asset or sector.
Comparing the weights of the minimum variance and risk parity portfolios, we can see that they have significant differences. The minimum variance portfolio puts the most weight on stock A, followed by MSFT, AAPL, BA, and META. In contrast, the risk parity portfolio allocates a more equal weight to all stocks, with the largest weight being given to AAPL, followed by MSFT, BA, A, and META.
As previously discussed, the minimum variance portfolio is designed to minimize the portfolio's volatility, while the risk parity portfolio aims to allocate risk equally among the assets in the portfolio. This means that the minimum variance portfolio may be more focused on achieving lower volatility, while the risk parity portfolio may be more focused on achieving a more diversified and balanced portfolio.
Without the weights for a maximum Sharpe ratio portfolio, we cannot make a direct comparison. However, it is important to note that the maximum Sharpe ratio portfolio aims to maximize the risk-adjusted return of the portfolio, and may therefore allocate more weight to assets with higher expected returns, even if they have higher volatility.
We should carefully consider their investment objectives, risk tolerance, and other individual factors before selecting a portfolio construction approach or combination of approaches. The optimal portfolio for each investor will depend on their unique circumstances and goals.
Finally,Based on the weights of the minimum variance and risk parity portfolios you provided earlier, we can see that:
For the minimum variance portfolio, stock A has the largest weight (51.4%), followed by MSFT (26.4%), AAPL (21.6%), BA (14.3%), and META (1.7%). This implies that the portfolio is heavily invested in stock A, which is a diversified global provider of healthcare products, and has a relatively lower weight for BA, which is an aerospace and defense company.
For the risk parity portfolio, AAPL has the largest weight (22.0%), followed by MSFT (22.4%), BA (16.7%), A (19.8%), and META (19.2%). This implies that the portfolio has a more balanced allocation among the stocks, with the largest weights given to technology companies AAPL and MSFT, and the smallest weight given to META.
It's important to note that the weights of a portfolio can change over time, depending on changes in the stock prices and other factors. Additionally, past performance is not indicative of future results, and investing in stocks always carries some level of risk. It's important for investors to conduct their own research and analysis, and to consult with a financial advisor before making any investment decisions.